﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace SuperKit
{

    public enum ThreadStatus {
        READY,
        PROCESS,
        COMPLETE
    }

    public abstract class ThreadToolItem {
        public ThreadStatus Status { get; set; }
        public string Command { get; private set; }
        public int ThreadIndex { get; set; }

        public ThreadToolItem() {
            Status = ThreadStatus.READY;
        }

        public void Start(string command) {
            Command = command;
            Status = ThreadStatus.PROCESS;
            Thread t = new Thread(OnStart);
            t.Start();
        }

        protected void OnStart() {            
            Process();
            Status = ThreadStatus.COMPLETE;
        }

        public bool IsCommand(string cmd) {
            return Kit.IsEqual(Command, cmd);
        }

        public abstract void Process();

        public virtual string GetStartMessage() {
            return null;
        }
    }

    public delegate void ThreadToolEvent();

    public class ThreadTool<T> where T : ThreadToolItem {
        public GeneralOutput Output { get; }
        public int MaxThread { get; set; }
        public List<T> Items { get; }
        public ThreadToolEvent OnComplete { get; private set; }
        public string Command { get; set; }

        public ThreadTool(int maxThread, GeneralOutput output) {
            this.Output = output;
            MaxThread = maxThread;
            Items = new List<T>();
            Command = string.Empty;
        }

        public void Start(string command = Kit.EMPTY, ThreadToolEvent onComplete = null) {
            this.OnComplete = onComplete;
            Command = command;
            OnProcess();
        }

        /*
         * 以非线程的方式执行所有的项目。就是依次执行
         */
        public void StartNonThread(string command = Kit.EMPTY, ThreadToolEvent onComplete = null) {
            this.OnComplete = onComplete;
            Command = command;
            foreach (var i in Items) {
                i.Process();
            }
        }

        public void StartSequence(string command = Kit.EMPTY) {
            Command = command;
            ResetStatus();
            foreach (var i in Items) {

                i.Start(command);
                FlushStartMessage(i);

                while (i.Status == ThreadStatus.PROCESS) {
                    Thread.Sleep(10);
                }

            }
        }

        public void StartThread(ThreadToolEvent onComplete) {
            this.OnComplete = onComplete;
            Thread t = new Thread(OnProcess);
            t.Start();
        }

        private void OnProcess() {
            ResetStatus();
            while (GetLeft() > 0) {
                StartItem();
                Thread.Sleep(10);
            }
            OnComplete?.Invoke();
        }

        private void ResetStatus() {
            foreach (var i in Items) {
                i.Status = ThreadStatus.READY;
            }
        }

        public void Add(T item) {
            item.ThreadIndex = Items.Count;
            Items.Add(item);
        }


        private void StartItem() {
            int running = GetRuuning();
            if (running >= MaxThread) {
                return;
            }
            foreach (var i in Items) {
                if (i.Status == ThreadStatus.READY) {
                    i.Status = ThreadStatus.PROCESS;
                    i.Start(Command);
                    FlushStartMessage(i);
                    
                    return;
                }
            }
        }

        public void FlushStartMessage(T i) {
            string msg = i.GetStartMessage();
            if (msg == null) {
                msg = string.Format("开始处理({0}/{1}):{2}", GetComplete(), Items.Count, i.ToString());
            }
            Output?.Invoke(msg);
        }

        public int GetRuuning() {
            int count = 0;
            foreach (var i in Items) {
                if (i.Status == ThreadStatus.PROCESS) {
                    count++;
                }
            }
            return count;
        }

        public int GetLeft() {
            int count = 0;
            foreach (var i in Items) {
                if (i.Status != ThreadStatus.COMPLETE) {
                    count++;
                }
            }
            return count;
        }

        public int GetComplete() {
            int count = 0;
            foreach (var i in Items) {
                if (i.Status == ThreadStatus.COMPLETE) {
                    count++;
                }
            }
            return count;
        }
    }
}
